////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2008 Michiel Helvensteijn                                    //
//                                                                            //
// This file is part of the Mist compiler.                                    //
//                                                                            //
// The Mist compiler is free software: you can redistribute it and/or modify  //
// it under the terms of the GNU General Public License as published by       //
// the Free Software Foundation, either version 3 of the License, or          //
// (at your option) any later version.                                        //
//                                                                            //
// The Mist compiler is distributed in the hope that it will be useful,       //
// but WITHOUT ANY WARRANTY; without even the implied warranty of             //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              //
// GNU General Public License for more details.                               //
//                                                                            //
// You should have received a copy of the GNU General Public License          //
// along with the Mist compiler.  If not, see <http://www.gnu.org/licenses/>. //
////////////////////////////////////////////////////////////////////////////////

#include "codelocation.hpp"

/******************************************************************************
 * Includes                                                                   *
 ******************************************************************************/

#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
using boost::make_tuple;

#include "location.hh"

/******************************************************************************
 * Function Implementations                                                   *
 ******************************************************************************/

CodeLocation::CodeLocation() {
} // intentionally empty

CodeLocation::CodeLocation(const yy::location& l) : _begin(l.begin), _end(l.end) {
	_end.set_column(_end.column() - 1);
}

CodeLocation::CodeLocation(const CodePosition& begin, const CodePosition& end) : _begin(begin), _end(end) {
} // intentionally empty

CodeLocation::CodeLocation(string beginFile, unsigned int beginLine, unsigned int beginColumn, string endFile, unsigned int endLine, unsigned int endColumn)
	: _begin(CodePosition(beginFile, beginLine, beginColumn)), _end(CodePosition(endFile, endLine, endColumn)) {
} // intentionally empty

CodeLocation::CodeLocation(string file, unsigned int beginLine, unsigned int beginColumn, unsigned int endLine, unsigned int endColumn)
	: _begin(CodePosition(file, beginLine, beginColumn)), _end(CodePosition(file, endLine, endColumn)) {
} // intentionally empty

CodeLocation::CodeLocation(string file, unsigned int line, unsigned int beginColumn, unsigned int endColumn)
	: _begin(CodePosition(file, line, beginColumn)), _end(CodePosition(file, line, endColumn)) {
} // intentionally empty

CodeLocation::CodeLocation(string file, unsigned int line, unsigned int column)
	: _begin(CodePosition(file, line, column)), _end(CodePosition(file, line, column)) {
} // intentionally empty

CodePosition& CodeLocation::begin() {
	return _begin;
}

CodePosition& CodeLocation::end() {
	return _end;
}

const CodePosition& CodeLocation::begin() const {
	return _begin;
}

const CodePosition& CodeLocation::end() const {
	return _end;
}

bool CodeLocation::is_in(const CodeLocation& other) const {
	return begin() >= other.begin()
	    && end()   <= other.end();
}

ostream& CodeLocation::report_to_stream(ostream& stream) const {
	if (begin().file() == end().file()) {
		if (!begin().file().empty())
			stream << begin().file() << ":";
		if (begin().line() == end().line()) {
			stream << begin().line();
			if (begin().column() == end().column()) {
				stream << ":" << begin().column();
			} else {
				stream << ": " << begin().column() << "-" << end().column();
			}
		} else {
			if (!begin().file().empty())
				stream << " ";
			stream << begin().line() << ":" << begin().column() << "-" << end().line() << ":" << end().column();
		}
	} else {
		stream << begin() << "-" << end();
	}
	
	return stream;
}

bool CodeLocation::operator<(const CodeLocation& other) const {
	return make_tuple(begin(), end()) < make_tuple(other.begin(), other.end());
}

bool CodeLocation::operator==(const CodeLocation& other) const {
	return (begin() == other.begin() && end() == other.end());
}

ostream& operator<<(ostream& stream, const CodeLocation& loc) {
	return loc.report_to_stream(stream);
}
